Pré-requisitos

Pacotes necessários:

#if(!require(PSF)) install.packages("PSF")
#if(!require(timetk)) remotes::install_github("business-science/timetk")
if(!require(EflowStats)) remotes::install_github("USGS-R/EflowStats")


pacotes <- c(
  "here",
  "usethis",
  "data.table",
  "HEobs",
#  "PSF",
  "tidyverse",
  "lubridate",
  "fs",
  "checkmate",
#  "xts",
#  "hydroGOF",
#  "ModelMetrics",
#  "forecast",
#  "timetk",
  "EflowStats",
  "hydrostats",
 #"NbClust",
 #  "cluster",  
 #  "cluster.datasets", 
  "cowplot", 
  # "clValid",
  "ggfortify", 
  #"clustree",
  #"dendextend",
  #"factoextra",
  #"FactoMineR",
  #"corrplot",
  #"GGally",
  #"ggiraphExtra",
  "kableExtra",
  "tidymodels",
  "fasstr"
)
# Carregar os pacotes
easypackages::libraries(pacotes)

Scripts:

source(here('R', 'load-data.R'))
source(here('R', 'utils.R'))

Dados de vazão

Os dados importados de vazão devem ser regularmente espaçados no tempo. Esta adequação das séries diárias, se necessária, pode ser realizada com a função complete_dates() do pacote {lhmetools}. Assim assegura-se que todas estações possuam 1 observação por dia e sem datas faltantes.

Metadados

data_link <- "https://www.dropbox.com/s/d40adhw66uwueet/VazoesNaturaisONS_D_87UHEsDirceuAssis_2018.dat?dl=1"
qnat_meta <- extract_metadata(NA_character_, informative = TRUE)
glimpse(qnat_meta)

Dados

qnat_data <- qnat_dly_ons() %>%
  select(date, qnat, code_stn) %>%
  lhmetools::complete_dates(group = "code_stn")
glimpse(qnat_data)

# Incluindo nome da estacao
qnat_data <- qnat_data %>%
  full_join(select(qnat_meta, estacao_codigo, nome_estacao),
            by = c(code_stn = "estacao_codigo")
            ) %>%
  rename("name_stn" = nome_estacao)

Assinaturas hidrológicas para 1 posto

Preparação dos dados para aplicação da função calc_magnifSeven com a opção de ano hidrológico (water year) para o posto 74 da ONS (G. B. Munhoz).

qnat_posto <- qnat_data %>% 
  sel_station(.,station = 74)  
glimpse(qnat_posto)
summary(qnat_posto)

magnif7(stn_data = select(qnat_posto, date, qnat))

Dados agrupados por postos

by_stn <- qnat_data %>% 
  group_by(code_stn) %>%
  nest()

Gráfico da sazonalidade da fração de vazão anual.

Fração mensal da vazão anual

# https://jcoliver.github.io/learn-r/008-ggplot-dendrograms-and-heatmaps.html
# glimpse(by_stn[["data"]][[1]])

q_mon_clim <- by_stn %>%
  unnest(cols = "data") %>%
  group_by(code_stn, month = lubridate::month(date)) %>%
  select(-name_stn) %>%
  summarise(q_med = mean(qnat, na.rm = TRUE))

q_ann_clim <- q_mon_clim %>%
  summarise(q_tot = sum(q_med))

q_mon_clim <- q_mon_clim %>% 
  full_join(q_ann_clim) %>%
  mutate(q_frac = q_med/q_tot * 100) %>%
  ungroup() %>%  
  mutate(code_stn = as.factor(code_stn),
         month = as.factor(month))
  
psych::describe(q_mon_clim) %>% 
  relocate(skew, kurtosis)

Agrupamento dos postos

qlong <- select(q_mon_clim, code_stn, month, q_frac) %>%
  pivot_wider(names_from = "month", 
              values_from = "q_frac",
              names_prefix = "qfrac_"
              )
qlong_scaled <- qlong 
qlong_scaled[,-1] <- scale(qlong_scaled[,-1])

# Run clustering
qmat <- as.matrix(qlong_scaled[, -1])
rownames(qmat) <- qlong_scaled$code_stn

clustd <- dist(x = qmat)
cd <- hclust(d = clustd, method="ward.D2")
#cd <- hclust(d = dist(x = qmat))
# optclus <- sapply(2:20, 
#                    function(i) 
#                      summary(cluster::silhouette(cutree(cd, k = i), clustd))$avg.width
#                    )
# optclus
# which.max(optclus) # 2
q_dendro <- as.dendrogram(cd)

# Create dendro
dendro_plot <- ggdendro::ggdendrogram(data = q_dendro, rotate = TRUE)+
   theme(axis.text.y = element_text(size = 8))

# Preview the plot
dendro_plot

# linhas da ordem dos postos
q_order <- order.dendrogram(q_dendro)
# ordem dos postos
as.integer(as.vector(qlong_scaled$code_stn[q_order]))

Heat map da fração mensal da vazão anual com postos ordenados pelo agrupamento.

q_mon_clim_trans <-  q_mon_clim %>%
  mutate(code_stn = factor(x = code_stn,
                               levels = qlong_scaled$code_stn[q_order], 
                               ordered = TRUE),
         q_frac = round((q_frac/2))*2
         )

# cbind(t = q_mon_clim_trans$q_frac, o = q_mon_clim$q_frac)
cols <- c("firebrick1", "lightpink3", "lightsteelblue3", 
          "cadetblue1", "cornflowerblue","blue", "navyblue")

q_mon_clim_trans %>%
  
  ggplot(aes(x = month, y = code_stn)) +
  geom_tile(aes(fill = q_frac), colour = "white") +
  #geom_tile(aes(fill = factor(q_frac)), colour = "white") +
  scale_x_discrete(expand = c(0,0)) +
  theme_bw() +
  #scale_fill_viridis_c()
  #scale_fill_viridis_c(guide = "legend")
  scale_fill_gradientn( "Vazão (% da média anual)",
                       colours = cols,
                       #guide = "legend",
                       breaks = seq(0, 20, by = 2)
                       ) +
  #scale_fill_manual(values = cols) +
  theme(legend.title = element_text(angle = 90, vjust = 1),
        legend.key.height = unit(1.5, units = "cm")
        )

    # scale_fill_distiller(
    #                      palette='RdYlBu', 
    #                      direction = 1,
    #                      breaks = seq(0, 20, by = 2),
    #                      #guide = "legend"
    #                     )
  
library(heatmaply)
index_cols <- c(8:12, 1:7) + 1
qdata <- as.data.frame(qlong[, index_cols])
names(qdata) <- tolower(month.abb[index_cols-1])

lut_postos <- qnat_data %>% 
  select(contains("stn")) %>% 
  distinct() 
postos <- lut_postos$name_stn
postos <- setNames(postos, lut_postos$code_stn)
  
rownames(qdata) <- postos[as.character(qlong$code_stn)]

heatmaply(qdata, 
          k_row = 4, 
          Colv = FALSE,
          #k_col = 3, 
          #scale = "column"
          scale_fill_gradient_fun = scale_fill_gradientn( "Vazão \n (% da média anual)",
                       colours = cols,
                       #guide = "legend",
                       breaks = seq(0, 20, by = 2)
                       ),
          fontsize_row = 5
          #seriate = "mean",
          #seriate = "OLO"
          #seriate = "GW"
          #seriate = "none"
          )

Testando fasstr

https://bcgov.github.io/fasstr/articles/fasstr.html

Será relevante considerar a diferenças nos períodos dos anos hidrológicos por posto?

check_season_plots <- qnat_data %>%
  rename("Date" = date) %>%
  fasstr::plot_daily_stats(
    values = "qnat",
    groups = "code_stn",
    start_year = 1991,
    end_year = 2010,
    log_discharge = TRUE,
    add_year = 2001, 
    complete_years = TRUE, 
    include_title = TRUE
  )
codes <- names(check_season_plots) %>%
  readr::parse_number()

lookup <- qnat_data %>% 
  select(contains("stn")) %>% 
  distinct() %>%
  slice(order(codes)) %>%
  arrange(code_stn)

plot_l <- map(seq_along(codes), 
    function(i) {
      # i = 1
      nm <- filter(lookup, code_stn == codes[i]) %>%
        pull(name_stn)
      check_season_plots[[i]] + ggtitle(paste0("Posto: ", nm))
    })
plot_l

Assinaturas hidrológicas para todos postos

seven_stats <- by_stn %>%
  #ungroup() %>%
  mutate(stats = purrr::map(data, ~.x %>% select(date, qnat) %>% magnif7))
seven_stats_tidy <- seven_stats %>%
  select(stats) %>%
  unnest(cols = "stats") %>%
  pivot_wider(names_from = indice, values_from = statistic) %>%
  ungroup()
seven_stats_tidy
saveRDS(seven_stats_tidy, file = here("output", "seven_stats.RDS"))
LS0tCnRpdGxlOiAiQXNzaW5hdHVyYXMgaGlkcm9sw7NnaWNhcyBwYXJhIGJhY2lhcyBoaWRyb2dyw6FmaWNhcyBkbyBTSU4iCmF1dGhvcjogIkpEVCIKZGF0ZTogIjI0LzA1LzIwMjEiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDogCiAgICB0b2M6IHllcwogIGh0bWxfbm90ZWJvb2s6IAogICAgdG9jOiB5ZXMKZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCiMjIFByw6ktcmVxdWlzaXRvcwoKUGFjb3RlcyBuZWNlc3PDoXJpb3M6CgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KI2lmKCFyZXF1aXJlKFBTRikpIGluc3RhbGwucGFja2FnZXMoIlBTRiIpCiNpZighcmVxdWlyZSh0aW1ldGspKSByZW1vdGVzOjppbnN0YWxsX2dpdGh1YigiYnVzaW5lc3Mtc2NpZW5jZS90aW1ldGsiKQppZighcmVxdWlyZShFZmxvd1N0YXRzKSkgcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoIlVTR1MtUi9FZmxvd1N0YXRzIikKCgpwYWNvdGVzIDwtIGMoCiAgImhlcmUiLAogICJ1c2V0aGlzIiwKICAiZGF0YS50YWJsZSIsCiAgIkhFb2JzIiwKIyAgIlBTRiIsCiAgInRpZHl2ZXJzZSIsCiAgImx1YnJpZGF0ZSIsCiAgImZzIiwKICAiY2hlY2ttYXRlIiwKIyAgInh0cyIsCiMgICJoeWRyb0dPRiIsCiMgICJNb2RlbE1ldHJpY3MiLAojICAiZm9yZWNhc3QiLAojICAidGltZXRrIiwKICAiRWZsb3dTdGF0cyIsCiAgImh5ZHJvc3RhdHMiLAogIyJOYkNsdXN0IiwKICMgICJjbHVzdGVyIiwgIAogIyAgImNsdXN0ZXIuZGF0YXNldHMiLCAKICAiY293cGxvdCIsIAogICMgImNsVmFsaWQiLAogICJnZ2ZvcnRpZnkiLCAKICAjImNsdXN0cmVlIiwKICAjImRlbmRleHRlbmQiLAogICMiZmFjdG9leHRyYSIsCiAgIyJGYWN0b01pbmVSIiwKICAjImNvcnJwbG90IiwKICAjIkdHYWxseSIsCiAgIyJnZ2lyYXBoRXh0cmEiLAogICJrYWJsZUV4dHJhIiwKICAidGlkeW1vZGVscyIsCiAgImZhc3N0ciIKKQojIENhcnJlZ2FyIG9zIHBhY290ZXMKZWFzeXBhY2thZ2VzOjpsaWJyYXJpZXMocGFjb3RlcykKYGBgCgpTY3JpcHRzOgoKYGBge3J9CnNvdXJjZShoZXJlKCdSJywgJ2xvYWQtZGF0YS5SJykpCnNvdXJjZShoZXJlKCdSJywgJ3V0aWxzLlInKSkKc291cmNlKGhlcmUoJ1InLCAncHJlcC1zdG4tZGF0YS5SJykpCmBgYAoKIyMgRGFkb3MgZGUgdmF6w6NvCgpPcyBkYWRvcyBpbXBvcnRhZG9zIGRlIHZhesOjbyBkZXZlbSBzZXIgcmVndWxhcm1lbnRlIGVzcGHDp2Fkb3Mgbm8gdGVtcG8uIEVzdGEgYWRlcXVhw6fDo28gZGFzIHPDqXJpZXMgZGnDoXJpYXMsIHNlIG5lY2Vzc8OhcmlhLCBwb2RlIHNlciByZWFsaXphZGEgY29tIGEgZnVuw6fDo28gYGNvbXBsZXRlX2RhdGVzKClgIGRvIHBhY290ZSAqKmB7bGhtZXRvb2xzfWAqKi4gQXNzaW0gYXNzZWd1cmEtc2UgcXVlIHRvZGFzIGVzdGHDp8O1ZXMgcG9zc3VhbSAxIG9ic2VydmHDp8OjbyBwb3IgZGlhIGUgc2VtIGRhdGFzIGZhbHRhbnRlcy4KCgpNZXRhZGFkb3MKCmBgYHtyfQpkYXRhX2xpbmsgPC0gImh0dHBzOi8vd3d3LmRyb3Bib3guY29tL3MvZDQwYWRodzY2dXd1ZWV0L1Zhem9lc05hdHVyYWlzT05TX0RfODdVSEVzRGlyY2V1QXNzaXNfMjAxOC5kYXQ/ZGw9MSIKcW5hdF9tZXRhIDwtIGV4dHJhY3RfbWV0YWRhdGEoTkFfY2hhcmFjdGVyXywgaW5mb3JtYXRpdmUgPSBUUlVFKQpnbGltcHNlKHFuYXRfbWV0YSkKYGBgCgoKRGFkb3MKCmBgYHtyfQpxbmF0X2RhdGEgPC0gcW5hdF9kbHlfb25zKCkgJT4lCiAgc2VsZWN0KGRhdGUsIHFuYXQsIGNvZGVfc3RuKSAlPiUKICBsaG1ldG9vbHM6OmNvbXBsZXRlX2RhdGVzKGdyb3VwID0gImNvZGVfc3RuIikKZ2xpbXBzZShxbmF0X2RhdGEpCgojIEluY2x1aW5kbyBub21lIGRhIGVzdGFjYW8KcW5hdF9kYXRhIDwtIHFuYXRfZGF0YSAlPiUKICBmdWxsX2pvaW4oc2VsZWN0KHFuYXRfbWV0YSwgZXN0YWNhb19jb2RpZ28sIG5vbWVfZXN0YWNhbyksCiAgICAgICAgICAgIGJ5ID0gYyhjb2RlX3N0biA9ICJlc3RhY2FvX2NvZGlnbyIpCiAgICAgICAgICAgICkgJT4lCiAgcmVuYW1lKCJuYW1lX3N0biIgPSBub21lX2VzdGFjYW8pCmBgYAoKIyMgQXNzaW5hdHVyYXMgaGlkcm9sw7NnaWNhcyBwYXJhIDEgcG9zdG8KCgoKClByZXBhcmHDp8OjbyBkb3MgZGFkb3MgcGFyYSBhcGxpY2HDp8OjbyBkYSBmdW7Dp8OjbyBgY2FsY19tYWduaWZTZXZlbmAgY29tIGEgb3DDp8OjbyBkZSBhbm8gaGlkcm9sw7NnaWNvICgqKndhdGVyIHllYXIqKikgcGFyYSBvIHBvc3RvIDc0IGRhIE9OUyAoRy4gQi4gTXVuaG96KS4KCmBgYHtyfQpxbmF0X3Bvc3RvIDwtIHFuYXRfZGF0YSAlPiUgCiAgc2VsX3N0YXRpb24oLixzdGF0aW9uID0gNzQpICAKZ2xpbXBzZShxbmF0X3Bvc3RvKQpzdW1tYXJ5KHFuYXRfcG9zdG8pCgptYWduaWY3KHN0bl9kYXRhID0gc2VsZWN0KHFuYXRfcG9zdG8sIGRhdGUsIHFuYXQpKQpgYGAKCgojIyBEYWRvcyBhZ3J1cGFkb3MgcG9yIHBvc3RvcwoKCgpgYGB7cn0KYnlfc3RuIDwtIHFuYXRfZGF0YSAlPiUgCiAgZ3JvdXBfYnkoY29kZV9zdG4pICU+JQogIG5lc3QoKQoKYGBgCgoKIyMjIEdyw6FmaWNvIGRhIHNhem9uYWxpZGFkZSBkYSBmcmHDp8OjbyBkZSB2YXrDo28gYW51YWwuCgpGcmHDp8OjbyBtZW5zYWwgZGEgdmF6w6NvIGFudWFsCgpgYGB7cn0KIyBodHRwczovL2pjb2xpdmVyLmdpdGh1Yi5pby9sZWFybi1yLzAwOC1nZ3Bsb3QtZGVuZHJvZ3JhbXMtYW5kLWhlYXRtYXBzLmh0bWwKIyBnbGltcHNlKGJ5X3N0bltbImRhdGEiXV1bWzFdXSkKCnFfbW9uX2NsaW0gPC0gYnlfc3RuICU+JQogIHVubmVzdChjb2xzID0gImRhdGEiKSAlPiUKICBncm91cF9ieShjb2RlX3N0biwgbW9udGggPSBsdWJyaWRhdGU6Om1vbnRoKGRhdGUpKSAlPiUKICBzZWxlY3QoLW5hbWVfc3RuKSAlPiUKICBzdW1tYXJpc2UocV9tZWQgPSBtZWFuKHFuYXQsIG5hLnJtID0gVFJVRSkpCgpxX2Fubl9jbGltIDwtIHFfbW9uX2NsaW0gJT4lCiAgc3VtbWFyaXNlKHFfdG90ID0gc3VtKHFfbWVkKSkKCnFfbW9uX2NsaW0gPC0gcV9tb25fY2xpbSAlPiUgCiAgZnVsbF9qb2luKHFfYW5uX2NsaW0pICU+JQogIG11dGF0ZShxX2ZyYWMgPSBxX21lZC9xX3RvdCAqIDEwMCkgJT4lCiAgdW5ncm91cCgpICU+JSAgCiAgbXV0YXRlKGNvZGVfc3RuID0gYXMuZmFjdG9yKGNvZGVfc3RuKSwKICAgICAgICAgbW9udGggPSBhcy5mYWN0b3IobW9udGgpKQogIApwc3ljaDo6ZGVzY3JpYmUocV9tb25fY2xpbSkgJT4lIAogIHJlbG9jYXRlKHNrZXcsIGt1cnRvc2lzKQpgYGAKCgpBZ3J1cGFtZW50byBkb3MgcG9zdG9zCgpgYGB7cn0KcWxvbmcgPC0gc2VsZWN0KHFfbW9uX2NsaW0sIGNvZGVfc3RuLCBtb250aCwgcV9mcmFjKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gIm1vbnRoIiwgCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSAicV9mcmFjIiwKICAgICAgICAgICAgICBuYW1lc19wcmVmaXggPSAicWZyYWNfIgogICAgICAgICAgICAgICkKcWxvbmdfc2NhbGVkIDwtIHFsb25nIApxbG9uZ19zY2FsZWRbLC0xXSA8LSBzY2FsZShxbG9uZ19zY2FsZWRbLC0xXSkKCiMgUnVuIGNsdXN0ZXJpbmcKcW1hdCA8LSBhcy5tYXRyaXgocWxvbmdfc2NhbGVkWywgLTFdKQpyb3duYW1lcyhxbWF0KSA8LSBxbG9uZ19zY2FsZWQkY29kZV9zdG4KCmNsdXN0ZCA8LSBkaXN0KHggPSBxbWF0KQpjZCA8LSBoY2x1c3QoZCA9IGNsdXN0ZCwgbWV0aG9kPSJ3YXJkLkQyIikKI2NkIDwtIGhjbHVzdChkID0gZGlzdCh4ID0gcW1hdCkpCiMgb3B0Y2x1cyA8LSBzYXBwbHkoMjoyMCwgCiMgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKGkpIAojICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcnkoY2x1c3Rlcjo6c2lsaG91ZXR0ZShjdXRyZWUoY2QsIGsgPSBpKSwgY2x1c3RkKSkkYXZnLndpZHRoCiMgICAgICAgICAgICAgICAgICAgICkKIyBvcHRjbHVzCiMgd2hpY2gubWF4KG9wdGNsdXMpICMgMgpxX2RlbmRybyA8LSBhcy5kZW5kcm9ncmFtKGNkKQoKIyBDcmVhdGUgZGVuZHJvCmRlbmRyb19wbG90IDwtIGdnZGVuZHJvOjpnZ2RlbmRyb2dyYW0oZGF0YSA9IHFfZGVuZHJvLCByb3RhdGUgPSBUUlVFKSsKICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKQoKIyBQcmV2aWV3IHRoZSBwbG90CmRlbmRyb19wbG90CgojIGxpbmhhcyBkYSBvcmRlbSBkb3MgcG9zdG9zCnFfb3JkZXIgPC0gb3JkZXIuZGVuZHJvZ3JhbShxX2RlbmRybykKIyBvcmRlbSBkb3MgcG9zdG9zCmFzLmludGVnZXIoYXMudmVjdG9yKHFsb25nX3NjYWxlZCRjb2RlX3N0bltxX29yZGVyXSkpCmBgYAoKSGVhdCBtYXAgZGEgZnJhw6fDo28gbWVuc2FsIGRhIHZhesOjbyBhbnVhbCBjb20gcG9zdG9zIG9yZGVuYWRvcyBwZWxvIGFncnVwYW1lbnRvLgoKYGBge3J9CnFfbW9uX2NsaW1fdHJhbnMgPC0gIHFfbW9uX2NsaW0gJT4lCiAgbXV0YXRlKGNvZGVfc3RuID0gZmFjdG9yKHggPSBjb2RlX3N0biwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHFsb25nX3NjYWxlZCRjb2RlX3N0bltxX29yZGVyXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmRlcmVkID0gVFJVRSksCiAgICAgICAgIHFfZnJhYyA9IHJvdW5kKChxX2ZyYWMvMikpKjIKICAgICAgICAgKQoKIyBjYmluZCh0ID0gcV9tb25fY2xpbV90cmFucyRxX2ZyYWMsIG8gPSBxX21vbl9jbGltJHFfZnJhYykKY29scyA8LSBjKCJmaXJlYnJpY2sxIiwgImxpZ2h0cGluazMiLCAibGlnaHRzdGVlbGJsdWUzIiwgCiAgICAgICAgICAiY2FkZXRibHVlMSIsICJjb3JuZmxvd2VyYmx1ZSIsImJsdWUiLCAibmF2eWJsdWUiKQoKcV9tb25fY2xpbV90cmFucyAlPiUKICAKICBnZ3Bsb3QoYWVzKHggPSBtb250aCwgeSA9IGNvZGVfc3RuKSkgKwogIGdlb21fdGlsZShhZXMoZmlsbCA9IHFfZnJhYyksIGNvbG91ciA9ICJ3aGl0ZSIpICsKICAjZ2VvbV90aWxlKGFlcyhmaWxsID0gZmFjdG9yKHFfZnJhYykpLCBjb2xvdXIgPSAid2hpdGUiKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShleHBhbmQgPSBjKDAsMCkpICsKICB0aGVtZV9idygpICsKICAjc2NhbGVfZmlsbF92aXJpZGlzX2MoKQogICNzY2FsZV9maWxsX3ZpcmlkaXNfYyhndWlkZSA9ICJsZWdlbmQiKQogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKCAiVmF6w6NvICglIGRhIG3DqWRpYSBhbnVhbCkiLAogICAgICAgICAgICAgICAgICAgICAgIGNvbG91cnMgPSBjb2xzLAogICAgICAgICAgICAgICAgICAgICAgICNndWlkZSA9ICJsZWdlbmQiLAogICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgwLCAyMCwgYnkgPSAyKQogICAgICAgICAgICAgICAgICAgICAgICkgKwogICNzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xzKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMSksCiAgICAgICAgbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDEuNSwgdW5pdHMgPSAiY20iKQogICAgICAgICkKCiAgICAjIHNjYWxlX2ZpbGxfZGlzdGlsbGVyKAogICAgIyAgICAgICAgICAgICAgICAgICAgICBwYWxldHRlPSdSZFlsQnUnLCAKICAgICMgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gMSwKICAgICMgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKDAsIDIwLCBieSA9IDIpLAogICAgIyAgICAgICAgICAgICAgICAgICAgICAjZ3VpZGUgPSAibGVnZW5kIgogICAgIyAgICAgICAgICAgICAgICAgICAgICkKICAKCgpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQpsaWJyYXJ5KGhlYXRtYXBseSkKaW5kZXhfY29scyA8LSBjKDg6MTIsIDE6NykgKyAxCnFkYXRhIDwtIGFzLmRhdGEuZnJhbWUocWxvbmdbLCBpbmRleF9jb2xzXSkKbmFtZXMocWRhdGEpIDwtIHRvbG93ZXIobW9udGguYWJiW2luZGV4X2NvbHMtMV0pCgpsdXRfcG9zdG9zIDwtIHFuYXRfZGF0YSAlPiUgCiAgc2VsZWN0KGNvbnRhaW5zKCJzdG4iKSkgJT4lIAogIGRpc3RpbmN0KCkgCnBvc3RvcyA8LSBsdXRfcG9zdG9zJG5hbWVfc3RuCnBvc3RvcyA8LSBzZXROYW1lcyhwb3N0b3MsIGx1dF9wb3N0b3MkY29kZV9zdG4pCiAgCnJvd25hbWVzKHFkYXRhKSA8LSBwb3N0b3NbYXMuY2hhcmFjdGVyKHFsb25nJGNvZGVfc3RuKV0KCmhlYXRtYXBseShxZGF0YSwgCiAgICAgICAgICBrX3JvdyA9IDQsIAogICAgICAgICAgQ29sdiA9IEZBTFNFLAogICAgICAgICAgI2tfY29sID0gMywgCiAgICAgICAgICAjc2NhbGUgPSAiY29sdW1uIgogICAgICAgICAgc2NhbGVfZmlsbF9ncmFkaWVudF9mdW4gPSBzY2FsZV9maWxsX2dyYWRpZW50biggIlZhesOjbyBcbiAoJSBkYSBtw6lkaWEgYW51YWwpIiwKICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXJzID0gY29scywKICAgICAgICAgICAgICAgICAgICAgICAjZ3VpZGUgPSAibGVnZW5kIiwKICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMCwgMjAsIGJ5ID0gMikKICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgZm9udHNpemVfcm93ID0gNgogICAgICAgICAgI3NlcmlhdGUgPSAibWVhbiIsCiAgICAgICAgICAjc2VyaWF0ZSA9ICJPTE8iCiAgICAgICAgICAjc2VyaWF0ZSA9ICJHVyIKICAgICAgICAgICNzZXJpYXRlID0gIm5vbmUiCiAgICAgICAgICApCmBgYAoKCiMjIFRlc3RhbmRvIGZhc3N0cgoKaHR0cHM6Ly9iY2dvdi5naXRodWIuaW8vZmFzc3RyL2FydGljbGVzL2Zhc3N0ci5odG1sCgpTZXLDoSByZWxldmFudGUgY29uc2lkZXJhciBhIGRpZmVyZW7Dp2FzIG5vcyBwZXLDrW9kb3MgZG9zIGFub3MgaGlkcm9sw7NnaWNvcyBwb3IgcG9zdG8/CgpgYGB7ciwgZXZhbCA9IEZBTFNFfQoKY2hlY2tfc2Vhc29uX3Bsb3RzIDwtIHFuYXRfZGF0YSAlPiUKICByZW5hbWUoIkRhdGUiID0gZGF0ZSkgJT4lCiAgZmFzc3RyOjpwbG90X2RhaWx5X3N0YXRzKAogICAgdmFsdWVzID0gInFuYXQiLAogICAgZ3JvdXBzID0gImNvZGVfc3RuIiwKICAgIHN0YXJ0X3llYXIgPSAxOTkxLAogICAgZW5kX3llYXIgPSAyMDEwLAogICAgbG9nX2Rpc2NoYXJnZSA9IFRSVUUsCiAgICBhZGRfeWVhciA9IDIwMDEsIAogICAgY29tcGxldGVfeWVhcnMgPSBUUlVFLCAKICAgIGluY2x1ZGVfdGl0bGUgPSBUUlVFCiAgKQoKCmBgYAoKCmBgYHtyLCBldmFsID0gRkFMU0V9CmNvZGVzIDwtIG5hbWVzKGNoZWNrX3NlYXNvbl9wbG90cykgJT4lCiAgcmVhZHI6OnBhcnNlX251bWJlcigpCgpsb29rdXAgPC0gcW5hdF9kYXRhICU+JSAKICBzZWxlY3QoY29udGFpbnMoInN0biIpKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUKICBzbGljZShvcmRlcihjb2RlcykpICU+JQogIGFycmFuZ2UoY29kZV9zdG4pCgpwbG90X2wgPC0gbWFwKHNlcV9hbG9uZyhjb2RlcyksIAogICAgZnVuY3Rpb24oaSkgewogICAgICAjIGkgPSAxCiAgICAgIG5tIDwtIGZpbHRlcihsb29rdXAsIGNvZGVfc3RuID09IGNvZGVzW2ldKSAlPiUKICAgICAgICBwdWxsKG5hbWVfc3RuKQogICAgICBjaGVja19zZWFzb25fcGxvdHNbW2ldXSArIGdndGl0bGUocGFzdGUwKCJQb3N0bzogIiwgbm0pKQogICAgfSkKcGxvdF9sCmBgYAoKIyMgQXNzaW5hdHVyYXMgaGlkcm9sw7NnaWNhcyBwYXJhIHRvZG9zIHBvc3RvcwoKCgpgYGB7cn0Kc2V2ZW5fc3RhdHMgPC0gYnlfc3RuICU+JQogICN1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKHN0YXRzID0gcHVycnI6Om1hcChkYXRhLCB+LnggJT4lIHNlbGVjdChkYXRlLCBxbmF0KSAlPiUgbWFnbmlmNykpCmBgYAoKCgpgYGB7cn0Kc2V2ZW5fc3RhdHNfdGlkeSA8LSBzZXZlbl9zdGF0cyAlPiUKICBzZWxlY3Qoc3RhdHMpICU+JQogIHVubmVzdChjb2xzID0gInN0YXRzIikgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGluZGljZSwgdmFsdWVzX2Zyb20gPSBzdGF0aXN0aWMpICU+JQogIHVuZ3JvdXAoKQpzZXZlbl9zdGF0c190aWR5CnNhdmVSRFMoc2V2ZW5fc3RhdHNfdGlkeSwgZmlsZSA9IGhlcmUoIm91dHB1dCIsICJzZXZlbl9zdGF0cy5SRFMiKSkKYGBgCgo=